﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using CLUBsInterpreter.ObjectTypes;

namespace CLUBsInterpreter.AST
{
	/**
	 * <summary>
	 * Describes an abstract statement node in the AST.
	 * </summary>
	 **/
	abstract class StatementNode : AbstractSyntaxTree
	{
		/**
		 * <summary>
		 * The line number in the source file where this statement occurred.
		 * </summary>
		 **/
		public uint LineNumber;
		/**
		 * <summary>
		 * The actual C# code to be executed at runtime when evaluating this statement.
		 * </summary>
		 **/
		public Action TranslatedMethod;

		public BlockNode ParentBlock
		{
			get
			{
				AbstractSyntaxTree par = this;
				while ((par = par.Parent) != null)
				{
					if (par is BlockNode)
					{
						return (BlockNode)par;
					}
				}
				return null;
			}
		}
	}

	/**
	 * <summary>
	 * Describes an abstract statement node that uses an identifier.
	 * </summary>
	 **/
	abstract class IdentifiableStatementNode : StatementNode
	{
		/**
		 * <summary>
		 * The identifier node associated with the statement.
		 * </summary>
		 **/
		public Identifier Ident;
	}

	/**
	 * <summary>
	 * Describes an assignment statement node.
	 * </summary>
	 **/
	class AssignStmtNode : IdentifiableStatementNode
	{
		/**
		 * <summary>
		 * The declaration node, if any, associated with the assignment.
		 * </summary>
		 **/
		public DeclStmtNode Declaration;
		/**
		 * <summary>
		 * The expression to be assigned to the identifier.
		 * </summary>
		 **/
		public ExpressionNode Expression;

		/**
		 * <see cref="AbstractSyntaxTree.Visit"/>
		 **/
		public override void Visit(Visitor v)
		{
			// Call the appropriate Visitor method
			if (m_visitedOnce)
				v.VisitAssignStmtNodeSecond(this);
			else
			{
				m_visitedOnce = true;
				v.VisitAssignStmtNode(this);
			}
		}

		public override void PrintTree(TextWriter outStream, int depth)
		{
			// Print the assign statement node
			outStream.WriteLine(AbstractSyntaxTree.TabDepth(depth) + "AssignStmtNode");
			// Print the identifier
			Ident.PrintTree(outStream, depth + 1);
			// Print the expression
			Expression.PrintTree(outStream, depth + 1);
		}
	}

	/**
	 * <summary>
	 * Describes a declaration statement node.
	 * </summary>
	 **/
	class DeclStmtNode : IdentifiableStatementNode
	{
		/**
		 * <summary>
		 * The type of the declaration.
		 * </summary>
		 **/
		public IdentifierType InferredType;

		/**
		 * <see cref="AbstractSyntaxTree.Visit"/>
		 **/
		public override void Visit(Visitor v)
		{
			// Call the appropriate Visitor method
			if (m_visitedOnce)
				v.VisitDeclStmtNodeSecond(this);
			else
			{
				m_visitedOnce = true;
				v.VisitDeclStmtNode(this);
			}
		}

		public override void PrintTree(TextWriter outStream, int depth)
		{
			// Print the declaration statement node
			outStream.WriteLine(AbstractSyntaxTree.TabDepth(depth) + "DeclStmtNode");
			// Print the identifier
			Ident.PrintTree(outStream, depth + 1);
		}
	}

	/**
	 * <summary>
	 * Describes a call statement node.
	 * </summary>
	 **/
	class CallStmtNode : IdentifiableStatementNode
	{
		// Tree structure
		/**
		 * <summary>
		 * The expression nodes given as parameters to the call.
		 * </summary>
		 **/
		public List<ExpressionNode> Parameters = new List<ExpressionNode>();

		// Tree decoration
		/**
		 * <summary>
		 * The return type of the call.
		 * </summary>
		 **/
		public IdentifierType ReturnType;
		/**
		 * <summary>
		 * The action object referenced by the identifier.
		 * </summary>
		 **/
		public CLUBsAction ActionObject;

		/**
		 * <see cref="AbstractSyntaxTree.Visit"/>
		 **/
		public override void Visit(Visitor v)
		{
			// Call the appropriate Visitor method
			if (m_visitedOnce)
				v.VisitCallStmtNodeSecond(this);
			else
			{
				m_visitedOnce = true;
				v.VisitCallStmtNode(this);
			}
		}

		public override void PrintTree(TextWriter outStream, int depth)
		{
			// Print the call statement node
			outStream.WriteLine(AbstractSyntaxTree.TabDepth(depth) + "CallStmtNode");
			// Print the identifier
			Ident.PrintTree(outStream, depth + 1);
			// Print all parameter expressions
			foreach (ExpressionNode exp in Parameters)
			{
				exp.PrintTree(outStream, depth + 1);
			}
		}
	}

	/**
	 * <summary>
	 * Describes an if statement node.
	 * </summary>
	 **/
	class IfStmtNode : StatementNode
	{
		/**
		 * <summary>
		 * The condition expression.
		 * </summary>
		 **/
		public ExpressionNode Condition;
		/**
		 * <summary>
		 * The body block node.
		 * </summary>
		 **/
		public BlockNode Body;

		/**
		 * <see cref="AbstractSyntaxTree.Visit"/>
		 **/
		public override void Visit(Visitor v)
		{
			// Call the appropriate Visitor method
			if (m_visitedOnce)
				v.VisitIfStmtNodeSecond(this);
			else
			{
				m_visitedOnce = true;
				v.VisitIfStmtNode(this);
			}
		}

		public override void PrintTree(TextWriter outStream, int depth)
		{
			// Print the if statement node
			outStream.WriteLine(AbstractSyntaxTree.TabDepth(depth) + "IfStmtNode");
			// Print the condition
			Condition.PrintTree(outStream, depth + 1);
			// Print the body
			Body.PrintTree(outStream, depth + 1);
		}
	}

	/**
	 * <summary>
	 * Describes a check (switch) statement.
	 * </summary>
	 **/
	class CheckStmtNode : StatementNode
	{
		/**
		 * <summary>
		 * The expression to be checked.
		 * </summary>
		 **/
		public ExpressionNode CheckedExpression;
		/**
		 * <summary>
		 * The case nodes to be checked against and possibly executed.
		 * </summary>
		 **/
		public List<CaseNode> Cases = new List<CaseNode>();

		/**
		 * <see cref="AbstractSyntaxTree.Visit"/>
		 **/
		public override void Visit(Visitor v)
		{
			// Call the appropriate Visitor method
			if (m_visitedOnce)
				v.VisitCheckStmtNodeSecond(this);
			else
			{
				m_visitedOnce = true;
				v.VisitCheckStmtNode(this);
			}
		}

		public override void PrintTree(TextWriter outStream, int depth)
		{
			// Print the check statement node
			outStream.WriteLine(AbstractSyntaxTree.TabDepth(depth) + "CheckStmtNode");
			// Print the checked expression
			CheckedExpression.PrintTree(outStream, depth + 1);
			// Print all cases
			foreach (CaseNode node in Cases)
			{
				node.PrintTree(outStream, depth + 1);
			}
		}
	}

	/**
	 * <summary>
	 * Describes a case node.
	 * </summary>
	 **/
	class CaseNode : BlockNode
	{
		/**
		 * <summary>
		 * The matching expression to check against the checked expression at runtime.
		 * </summary>
		 **/
		public ExpressionNode MatchExpression;
		/**
		 * <summary>
		 * The line number in the source file where this case occurred.
		 * </summary>
		 **/
		public uint LineNumber;

		/**
		 * <see cref="AbstractSyntaxTree.Visit"/>
		 **/
		public override void Visit(Visitor v)
		{
			// Call the appropriate Visitor method
			if (m_visitedOnce)
				v.VisitCaseNodeSecond(this);
			else
			{
				m_visitedOnce = true;
				v.VisitCaseNode(this);
			}
		}

		public override void PrintTree(TextWriter outStream, int depth)
		{
			// Print the case node
			outStream.WriteLine(AbstractSyntaxTree.TabDepth(depth) + "CaseNode");
			// Print the matched expression
			MatchExpression.PrintTree(outStream, depth + 1);
			// Print the block
			base.PrintTree(outStream, depth + 1);
		}
	}

	/**
	 * <summary>
	 * Describes a while statement node.
	 * </summary>
	 **/
	class WhileStmtNode : StatementNode
	{
		/**
		 * <summary>
		 * The condition expression.
		 * </summary>
		 **/
		public ExpressionNode Condition;
		/**
		 * <summary>
		 * The body block node.
		 * </summary>
		 **/
		public BlockNode Body;

		/**
		 * <see cref="AbstractSyntaxTree.Visit"/>
		 **/
		public override void Visit(Visitor v)
		{
			// Call the appropriate Visitor method
			if (m_visitedOnce)
				v.VisitWhileStmtNodeSecond(this);
			else
			{
				m_visitedOnce = true;
				v.VisitWhileStmtNode(this);
			}
		}

		public override void PrintTree(TextWriter outStream, int depth)
		{
			// Print the while statement node
			outStream.WriteLine(AbstractSyntaxTree.TabDepth(depth) + "WhileStmtNode");
			// Print the condition
			Condition.PrintTree(outStream, depth + 1);
			// Print the block
			Body.PrintTree(outStream, depth + 1);
		}
	}

	/**
	 * <summary>
	 * Describes a for statement node.
	 * </summary>
	 **/
	class ForStmtNode : StatementNode
	{
		/**
		 * <summary>
		 * The initialization statement.
		 * </summary>
		 **/
		public StatementNode Initialize;
		/**
		 * <summary>
		 * The condition expression.
		 * </summary>
		 **/
		public ExpressionNode Condition;
		/**
		 * <summary>
		 * The incrementer statement.
		 * </summary>
		 **/
		public StatementNode Increment;
		/**
		 * <summary>
		 * The body block node.
		 * </summary>
		 **/
		public BlockNode Body;

		/**
		 * <see cref="AbstractSyntaxTree.Visit"/>
		 **/
		public override void Visit(Visitor v)
		{
			// Call the appropriate Visitor method
			if (m_visitedOnce)
				v.VisitForStmtNodeSecond(this);
			else
			{
				m_visitedOnce = true;
				v.VisitForStmtNode(this);
			}
		}

		public override void PrintTree(TextWriter outStream, int depth)
		{
			// Print the for statement node
			outStream.WriteLine(AbstractSyntaxTree.TabDepth(depth) + "ForStmtNode");
			// Print the initialization statement
			Initialize.PrintTree(outStream, depth + 1);
			// Print the condition
			Condition.PrintTree(outStream, depth + 1);
			// Print the incrementer statement
			Increment.PrintTree(outStream, depth + 1);
			// Print the block
			Body.PrintTree(outStream, depth + 1);
		}
	}

}
